package org.xingole.jgit.utils;

/**
 * <p>Handy utility functions to parse raw object contents.</p>
 *
 * <p>In Git, a raw object is an object that has not been compressed or pretty-printed.
 *    This means that it is stored in its raw binary format(byte array), and its contents(String text) are not
 *    accessible to the user.</p>
 */
public class RawParseUtils {
    // Matching methods
    /**
     * Determine if dst[ptr] matches src.
     * @param dst - the buffer to scan.
     * @param ptr - first position within dst, this should match src[0].
     * @param src - the buffer to test for equality with dst.
     * @return : ptr + src.length if dst[ptr...src.length] == src; else returns -1.
     */
    public static final int match(final byte[] dst, int ptr, final byte[] src) {
        // the overflow of the number of elements to compare with
        if(ptr + src.length > dst.length)
            return -1;

        // compare the corresponding elements of the src with the ones from the dst beginning with the ptr position.
        for(int i = 0; i < src.length; i++, ptr++) {
            if(dst[ptr] != src[i])
                return -1;       // not matched
        }
        return ptr;              // matched
    }

    // Formatting methods
    private static final byte[] base10byte = {'0', '1','2', '3', '4', '5',
            '6', '7', '8', '9' };
    /**
     * <p>Format a base 10 numeric into a temporary buffer.</p>
     *
     * <p>Formatting is performed backwards. The method starts at offset <code>offset - 1</code> and
     * ends at <code>offset - 1 - digits</code>, where <code>digits</code> is the number of positions necessary
     * to store the base 10 value.</p>
     *
     * <p>The argument and return values from this method make it easy to chain writing, for example:</p>
     * <pre>
     *     final byte[] tmp = new byte[64];
     *     int ptr = tmp.length;
     *     tmp[--ptr] = '\n';
     *     ptr = RawParseUtils.formatBase10(tmp, ptr, 32);
     *     tmp[--ptr] = ' ';
     *     ptr = RawParseUtils.formatBase10(tmp, ptr, 18);
     *     tmp[--ptr] = 0;
     *     final String str = new String(tmp, ptr, tmp.length - ptr);
     * </pre>
     *
     * <p>This method is to do:</p>
     *
     *  value => decimal integer, for example 36
     *
     *  buf: high       offset                 low
     *         |---------|----------------------|
     *                           ---> the direction to write the buffer
     *  offset: represents the last writing end at the location. The new writing should start at the offset next location.
     * @param buf - buffer to write into.
     * @param offset - one offset past the location where writing will begin; writing proceeds towards lower index values.
     * @param value - the value to store
     * @return : the new offset value <code>offset</code>. This is the position of the last byte written.
     *           Additional writing should start at one position earlier.
     */
    public static int formatBase10(final byte[] buf, int offset, int value) {
        // The boundary condition: if the value is equal to zero(0), then we don't need to parse the value => fetch digits
        if(value == 0) {
            buf[--offset] = '0';
            return offset;
        }

        // The negative and positive number have different processing, so we need to consider them respectively.
        final boolean isneg = value < 0;
        if(isneg)               // Of course, the codes can be viewed as the absolute value operation.
            value = -value;     // For negative number, process the number part firstly.
        while(value != 0) {
            buf[--offset] = base10byte[value % 10];   // value % 10 => extract the last bit digit, the same as the index.
            value /= 10;
        }

        if(isneg)
            buf[--offset] = '-';  // the - sign is added to the low index.
        return offset;
    }
}
